{
  "cells": [
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:25.356538Z",
          "start_time": "2025-01-17T01:58:25.352155Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "qny59IiONdAA",
        "outputId": "4b458e0a-f28e-47f6-b789-568b0f58d2d8"
      },
      "source": [
        "import matplotlib as mpl\n",
        "import matplotlib.pyplot as plt\n",
        "%matplotlib inline\n",
        "import numpy as np\n",
        "import sklearn\n",
        "import pandas as pd\n",
        "import os\n",
        "import sys\n",
        "import time\n",
        "from tqdm.auto import tqdm\n",
        "import torch\n",
        "import torch.nn as nn\n",
        "import torch.nn.functional as F\n",
        "\n",
        "print(sys.version_info)\n",
        "for module in mpl, np, pd, sklearn, torch:\n",
        "    print(module.__name__, module.__version__)\n",
        "\n",
        "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
        "print(device)\n"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "sys.version_info(major=3, minor=11, micro=11, releaselevel='final', serial=0)\n",
            "matplotlib 3.10.0\n",
            "numpy 1.26.4\n",
            "pandas 2.2.2\n",
            "sklearn 1.6.0\n",
            "torch 2.5.1+cu121\n",
            "cuda:0\n"
          ]
        }
      ],
      "execution_count": 1
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Y_nn_KMRNdAO"
      },
      "source": [
        "## 加载数据"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:25.399767Z",
          "start_time": "2025-01-17T01:58:25.368588Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xQYveEX6NdAS",
        "outputId": "50b04962-4818-4763-eb4e-c43b85857463"
      },
      "source": [
        "from torchvision import datasets\n",
        "from torchvision.transforms import ToTensor\n",
        "\n",
        "# fashion_mnist图像分类数据集\n",
        "train_ds = datasets.FashionMNIST(\n",
        "    root=\"data\",\n",
        "    train=True,\n",
        "    download=True,\n",
        "    transform=ToTensor()\n",
        ")\n",
        "\n",
        "test_ds = datasets.FashionMNIST(\n",
        "    root=\"data\",\n",
        "    train=False,\n",
        "    download=True,\n",
        "    transform=ToTensor()\n",
        ")\n",
        "\n",
        "# torchvision 数据集里没有提供训练集和验证集的划分\n",
        "# 当然也可以用 torch.utils.data.Dataset 实现人为划分\n",
        "# 从数据集到dataloader\n",
        "train_loader = torch.utils.data.DataLoader(train_ds, batch_size=16, shuffle=True)\n",
        "val_loader = torch.utils.data.DataLoader(test_ds, batch_size=16, shuffle=False)"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-images-idx3-ubyte.gz to data/FashionMNIST/raw/train-images-idx3-ubyte.gz\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "100%|██████████| 26.4M/26.4M [00:00<00:00, 72.8MB/s]\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Extracting data/FashionMNIST/raw/train-images-idx3-ubyte.gz to data/FashionMNIST/raw\n",
            "\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-labels-idx1-ubyte.gz\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/train-labels-idx1-ubyte.gz to data/FashionMNIST/raw/train-labels-idx1-ubyte.gz\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "100%|██████████| 29.5k/29.5k [00:00<00:00, 5.80MB/s]"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Extracting data/FashionMNIST/raw/train-labels-idx1-ubyte.gz to data/FashionMNIST/raw\n",
            "\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-images-idx3-ubyte.gz\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-images-idx3-ubyte.gz to data/FashionMNIST/raw/t10k-images-idx3-ubyte.gz\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "\n",
            "100%|██████████| 4.42M/4.42M [00:00<00:00, 67.8MB/s]\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Extracting data/FashionMNIST/raw/t10k-images-idx3-ubyte.gz to data/FashionMNIST/raw\n",
            "\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz\n",
            "Downloading http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/t10k-labels-idx1-ubyte.gz to data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stderr",
          "text": [
            "100%|██████████| 5.15k/5.15k [00:00<00:00, 7.83MB/s]\n"
          ]
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Extracting data/FashionMNIST/raw/t10k-labels-idx1-ubyte.gz to data/FashionMNIST/raw\n",
            "\n"
          ]
        }
      ],
      "execution_count": 2
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:25.403025Z",
          "start_time": "2025-01-17T01:58:25.399767Z"
        },
        "id": "IDZdyrz9NdAU"
      },
      "source": [
        "from torchvision.transforms import Normalize\n",
        "\n",
        "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
        "def cal_mean_std(ds):\n",
        "    mean = 0.\n",
        "    std = 0.\n",
        "    for img, _ in ds:\n",
        "        mean += img.mean(dim=(1, 2))\n",
        "        std += img.std(dim=(1, 2))\n",
        "    mean /= len(ds)\n",
        "    std /= len(ds)\n",
        "    return mean, std\n",
        "\n",
        "\n",
        "# print(cal_mean_std(train_ds))\n",
        "# 0.2860， 0.3205\n",
        "transforms = nn.Sequential(\n",
        "    Normalize([0.2860], [0.3205])\n",
        ")\n"
      ],
      "outputs": [],
      "execution_count": 3
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cx_82RwBNdAV"
      },
      "source": [
        "## 定义模型\n",
        "\n",
        "这里我们没有用`nn.Linear`的默认初始化，而是采用了xavier均匀分布去初始化全连接层的权重\n",
        "\n",
        "xavier初始化出自论文 《Understanding the difficulty of training deep feedforward neural networks》，适用于使用`tanh`和`sigmoid`激活函数的方法。当然，我们这里的模型采用的是`relu`激活函数，采用He初始化（何凯明初始化）会更加合适。感兴趣的同学可以自己动手修改并比对效果。\n",
        "\n",
        "|神经网络层数|初始化方式|early stop at epoch| val_loss | vla_acc|\n",
        "|-|-|-|-|-|\n",
        "|20|默认|\n",
        "|20|xaviier_uniform|\n",
        "|20|he_uniform|\n",
        "|...|\n",
        "\n",
        "He初始化出自论文 《Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification》"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:25.413218Z",
          "start_time": "2025-01-17T01:58:25.403025Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dwc4kYNINdAW",
        "outputId": "117e2a32-4081-4e94-f314-2ba86562a381"
      },
      "source": [
        "class NeuralNetwork(nn.Module):\n",
        "    def __init__(self, layers_num=2):\n",
        "        super().__init__()\n",
        "        self.transforms = transforms\n",
        "        self.flatten = nn.Flatten()\n",
        "        # 多加几层\n",
        "        self.linear_relu_stack = nn.Sequential(\n",
        "            nn.Linear(28 * 28, 100),  # in_features=784, out_features=300\n",
        "            # 一般而言，先batch norm 后 激活函数\n",
        "            # 参见论文 《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》\n",
        "            nn.BatchNorm1d(100),  # num of features=100\n",
        "            nn.ReLU(),\n",
        "        )\n",
        "        # 加19层\n",
        "        for i in range(1, layers_num):\n",
        "            self.linear_relu_stack.add_module(f\"Linear_{i}\", nn.Linear(100, 100))\n",
        "            self.linear_relu_stack.add_module(f\"batchnorm_{i}\", nn.BatchNorm1d(100)) #因为特征是1维的，所以用1维的batchnorm\n",
        "            self.linear_relu_stack.add_module(f\"relu\", nn.ReLU())\n",
        "        # 输出层\n",
        "        self.linear_relu_stack.add_module(\"Output Layer\", nn.Linear(100, 10))\n",
        "\n",
        "        self.init_weights()\n",
        "\n",
        "    def init_weights(self):\n",
        "        \"\"\"使用 xavier 均匀分布来初始化全连接层的权重 W\"\"\"\n",
        "        for m in self.modules():\n",
        "            if isinstance(m, nn.Linear):\n",
        "                nn.init.xavier_uniform_(m.weight)\n",
        "                nn.init.zeros_(m.bias)\n",
        "\n",
        "    def forward(self, x):\n",
        "        # x.shape [batch size, 1, 28, 28]\n",
        "        x = self.transforms(x)\n",
        "        x = self.flatten(x)\n",
        "        # 展平后 x.shape [batch size, 28 * 28]\n",
        "        logits = self.linear_relu_stack(x)\n",
        "        # logits.shape [batch size, 10]\n",
        "        return logits\n",
        "\n",
        "print(f\"{'layer_name':^40}\\tparamerters num\")\n",
        "total_params = 0\n",
        "for idx, (key, value) in enumerate(NeuralNetwork(20).named_parameters()):\n",
        "    print(\"{}{:<40}\\t{:^10}\".format(idx,key, np.prod(value.shape)))\n",
        "    total_params += np.prod(value.shape)\n",
        "total_params"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "               layer_name               \tparamerters num\n",
            "0linear_relu_stack.0.weight              \t  78400   \n",
            "1linear_relu_stack.0.bias                \t   100    \n",
            "2linear_relu_stack.1.weight              \t   100    \n",
            "3linear_relu_stack.1.bias                \t   100    \n",
            "4linear_relu_stack.Linear_1.weight       \t  10000   \n",
            "5linear_relu_stack.Linear_1.bias         \t   100    \n",
            "6linear_relu_stack.batchnorm_1.weight    \t   100    \n",
            "7linear_relu_stack.batchnorm_1.bias      \t   100    \n",
            "8linear_relu_stack.Linear_2.weight       \t  10000   \n",
            "9linear_relu_stack.Linear_2.bias         \t   100    \n",
            "10linear_relu_stack.batchnorm_2.weight    \t   100    \n",
            "11linear_relu_stack.batchnorm_2.bias      \t   100    \n",
            "12linear_relu_stack.Linear_3.weight       \t  10000   \n",
            "13linear_relu_stack.Linear_3.bias         \t   100    \n",
            "14linear_relu_stack.batchnorm_3.weight    \t   100    \n",
            "15linear_relu_stack.batchnorm_3.bias      \t   100    \n",
            "16linear_relu_stack.Linear_4.weight       \t  10000   \n",
            "17linear_relu_stack.Linear_4.bias         \t   100    \n",
            "18linear_relu_stack.batchnorm_4.weight    \t   100    \n",
            "19linear_relu_stack.batchnorm_4.bias      \t   100    \n",
            "20linear_relu_stack.Linear_5.weight       \t  10000   \n",
            "21linear_relu_stack.Linear_5.bias         \t   100    \n",
            "22linear_relu_stack.batchnorm_5.weight    \t   100    \n",
            "23linear_relu_stack.batchnorm_5.bias      \t   100    \n",
            "24linear_relu_stack.Linear_6.weight       \t  10000   \n",
            "25linear_relu_stack.Linear_6.bias         \t   100    \n",
            "26linear_relu_stack.batchnorm_6.weight    \t   100    \n",
            "27linear_relu_stack.batchnorm_6.bias      \t   100    \n",
            "28linear_relu_stack.Linear_7.weight       \t  10000   \n",
            "29linear_relu_stack.Linear_7.bias         \t   100    \n",
            "30linear_relu_stack.batchnorm_7.weight    \t   100    \n",
            "31linear_relu_stack.batchnorm_7.bias      \t   100    \n",
            "32linear_relu_stack.Linear_8.weight       \t  10000   \n",
            "33linear_relu_stack.Linear_8.bias         \t   100    \n",
            "34linear_relu_stack.batchnorm_8.weight    \t   100    \n",
            "35linear_relu_stack.batchnorm_8.bias      \t   100    \n",
            "36linear_relu_stack.Linear_9.weight       \t  10000   \n",
            "37linear_relu_stack.Linear_9.bias         \t   100    \n",
            "38linear_relu_stack.batchnorm_9.weight    \t   100    \n",
            "39linear_relu_stack.batchnorm_9.bias      \t   100    \n",
            "40linear_relu_stack.Linear_10.weight      \t  10000   \n",
            "41linear_relu_stack.Linear_10.bias        \t   100    \n",
            "42linear_relu_stack.batchnorm_10.weight   \t   100    \n",
            "43linear_relu_stack.batchnorm_10.bias     \t   100    \n",
            "44linear_relu_stack.Linear_11.weight      \t  10000   \n",
            "45linear_relu_stack.Linear_11.bias        \t   100    \n",
            "46linear_relu_stack.batchnorm_11.weight   \t   100    \n",
            "47linear_relu_stack.batchnorm_11.bias     \t   100    \n",
            "48linear_relu_stack.Linear_12.weight      \t  10000   \n",
            "49linear_relu_stack.Linear_12.bias        \t   100    \n",
            "50linear_relu_stack.batchnorm_12.weight   \t   100    \n",
            "51linear_relu_stack.batchnorm_12.bias     \t   100    \n",
            "52linear_relu_stack.Linear_13.weight      \t  10000   \n",
            "53linear_relu_stack.Linear_13.bias        \t   100    \n",
            "54linear_relu_stack.batchnorm_13.weight   \t   100    \n",
            "55linear_relu_stack.batchnorm_13.bias     \t   100    \n",
            "56linear_relu_stack.Linear_14.weight      \t  10000   \n",
            "57linear_relu_stack.Linear_14.bias        \t   100    \n",
            "58linear_relu_stack.batchnorm_14.weight   \t   100    \n",
            "59linear_relu_stack.batchnorm_14.bias     \t   100    \n",
            "60linear_relu_stack.Linear_15.weight      \t  10000   \n",
            "61linear_relu_stack.Linear_15.bias        \t   100    \n",
            "62linear_relu_stack.batchnorm_15.weight   \t   100    \n",
            "63linear_relu_stack.batchnorm_15.bias     \t   100    \n",
            "64linear_relu_stack.Linear_16.weight      \t  10000   \n",
            "65linear_relu_stack.Linear_16.bias        \t   100    \n",
            "66linear_relu_stack.batchnorm_16.weight   \t   100    \n",
            "67linear_relu_stack.batchnorm_16.bias     \t   100    \n",
            "68linear_relu_stack.Linear_17.weight      \t  10000   \n",
            "69linear_relu_stack.Linear_17.bias        \t   100    \n",
            "70linear_relu_stack.batchnorm_17.weight   \t   100    \n",
            "71linear_relu_stack.batchnorm_17.bias     \t   100    \n",
            "72linear_relu_stack.Linear_18.weight      \t  10000   \n",
            "73linear_relu_stack.Linear_18.bias        \t   100    \n",
            "74linear_relu_stack.batchnorm_18.weight   \t   100    \n",
            "75linear_relu_stack.batchnorm_18.bias     \t   100    \n",
            "76linear_relu_stack.Linear_19.weight      \t  10000   \n",
            "77linear_relu_stack.Linear_19.bias        \t   100    \n",
            "78linear_relu_stack.batchnorm_19.weight   \t   100    \n",
            "79linear_relu_stack.batchnorm_19.bias     \t   100    \n",
            "80linear_relu_stack.Output Layer.weight   \t   1000   \n",
            "81linear_relu_stack.Output Layer.bias     \t    10    \n"
          ]
        },
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "275410"
            ]
          },
          "metadata": {},
          "execution_count": 4
        }
      ],
      "execution_count": 4
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3n5fNafBNdAY"
      },
      "source": [
        "## 训练"
      ]
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:25.452431Z",
          "start_time": "2025-01-17T01:58:25.413218Z"
        },
        "id": "BLeIVC5dNdAZ"
      },
      "source": [
        "from sklearn.metrics import accuracy_score\n",
        "\n",
        "@torch.no_grad()\n",
        "def evaluating(model, dataloader, loss_fct):\n",
        "    loss_list = []\n",
        "    pred_list = []\n",
        "    label_list = []\n",
        "    for datas, labels in dataloader:\n",
        "        datas = datas.to(device)\n",
        "        labels = labels.to(device)\n",
        "        # 前向计算\n",
        "        logits = model(datas)\n",
        "        loss = loss_fct(logits, labels)         # 验证集损失\n",
        "        loss_list.append(loss.item())\n",
        "\n",
        "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
        "        pred_list.extend(preds.cpu().numpy().tolist())\n",
        "        label_list.extend(labels.cpu().numpy().tolist())\n",
        "\n",
        "    acc = accuracy_score(label_list, pred_list)\n",
        "    return np.mean(loss_list), acc\n"
      ],
      "outputs": [],
      "execution_count": 5
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:27.747687Z",
          "start_time": "2025-01-17T01:58:25.452431Z"
        },
        "id": "4plCIMMENdAb"
      },
      "source": [
        "from torch.utils.tensorboard import SummaryWriter\n",
        "\n",
        "\n",
        "class TensorBoardCallback:\n",
        "    def __init__(self, log_dir, flush_secs=10):\n",
        "        \"\"\"\n",
        "        Args:\n",
        "            log_dir (str): dir to write log.\n",
        "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
        "        \"\"\"\n",
        "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
        "\n",
        "    def draw_model(self, model, input_shape):\n",
        "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
        "\n",
        "    def add_loss_scalars(self, step, loss, val_loss):\n",
        "        self.writer.add_scalars(\n",
        "            main_tag=\"training/loss\",\n",
        "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
        "            global_step=step,\n",
        "            )\n",
        "\n",
        "    def add_acc_scalars(self, step, acc, val_acc):\n",
        "        self.writer.add_scalars(\n",
        "            main_tag=\"training/accuracy\",\n",
        "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
        "            global_step=step,\n",
        "        )\n",
        "\n",
        "    def add_lr_scalars(self, step, learning_rate):\n",
        "        self.writer.add_scalars(\n",
        "            main_tag=\"training/learning_rate\",\n",
        "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
        "            global_step=step,\n",
        "\n",
        "        )\n",
        "\n",
        "    def __call__(self, step, **kwargs):\n",
        "        # add loss\n",
        "        loss = kwargs.pop(\"loss\", None)\n",
        "        val_loss = kwargs.pop(\"val_loss\", None)\n",
        "        if loss is not None and val_loss is not None:\n",
        "            self.add_loss_scalars(step, loss, val_loss)\n",
        "        # add acc\n",
        "        acc = kwargs.pop(\"acc\", None)\n",
        "        val_acc = kwargs.pop(\"val_acc\", None)\n",
        "        if acc is not None and val_acc is not None:\n",
        "            self.add_acc_scalars(step, acc, val_acc)\n",
        "        # add lr\n",
        "        learning_rate = kwargs.pop(\"lr\", None)\n",
        "        if learning_rate is not None:\n",
        "            self.add_lr_scalars(step, learning_rate)\n"
      ],
      "outputs": [],
      "execution_count": 6
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:27.752691Z",
          "start_time": "2025-01-17T01:58:27.748692Z"
        },
        "id": "Yo27p_nYNdAc"
      },
      "source": [
        "class SaveCheckpointsCallback:\n",
        "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
        "        \"\"\"\n",
        "        Save checkpoints each save_epoch epoch.\n",
        "        We save checkpoint by epoch in this implementation.\n",
        "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
        "\n",
        "        Args:\n",
        "            save_dir (str): dir to save checkpoint\n",
        "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
        "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
        "        \"\"\"\n",
        "        self.save_dir = save_dir\n",
        "        self.save_step = save_step\n",
        "        self.save_best_only = save_best_only\n",
        "        self.best_metrics = -1\n",
        "\n",
        "        # mkdir\n",
        "        if not os.path.exists(self.save_dir):\n",
        "            os.makedirs(self.save_dir) #makedirs 创建多层目录\n",
        "\n",
        "    def __call__(self, step, state_dict, metric=None):\n",
        "        if step % self.save_step > 0:\n",
        "            return\n",
        "\n",
        "        if self.save_best_only:\n",
        "            assert metric is not None\n",
        "            if metric >= self.best_metrics:\n",
        "                # save checkpoints\n",
        "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
        "                # update best metrics\n",
        "                self.best_metrics = metric\n",
        "        else:\n",
        "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
        "\n"
      ],
      "outputs": [],
      "execution_count": 7
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:27.762393Z",
          "start_time": "2025-01-17T01:58:27.753194Z"
        },
        "id": "RqGvtSWUNdAd"
      },
      "source": [
        "class EarlyStopCallback:\n",
        "    def __init__(self, patience=5, min_delta=0.01):\n",
        "        \"\"\"\n",
        "\n",
        "        Args:\n",
        "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
        "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute\n",
        "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
        "        \"\"\"\n",
        "        self.patience = patience\n",
        "        self.min_delta = min_delta\n",
        "        self.best_metric = -1\n",
        "        self.counter = 0\n",
        "\n",
        "    def __call__(self, metric):\n",
        "        if metric >= self.best_metric + self.min_delta:\n",
        "            # update best metric\n",
        "            self.best_metric = metric\n",
        "            # reset counter\n",
        "            self.counter = 0\n",
        "        else:\n",
        "            self.counter += 1\n",
        "\n",
        "    @property\n",
        "    def early_stop(self):\n",
        "        return self.counter >= self.patience\n"
      ],
      "outputs": [],
      "execution_count": 8
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:27.769593Z",
          "start_time": "2025-01-17T01:58:27.762935Z"
        },
        "id": "1_JGCREINdAe"
      },
      "source": [
        "# 训练\n",
        "def training(\n",
        "    model,\n",
        "    train_loader,\n",
        "    val_loader,\n",
        "    epoch,\n",
        "    loss_fct,\n",
        "    optimizer,\n",
        "    tensorboard_callback=None,\n",
        "    save_ckpt_callback=None,\n",
        "    early_stop_callback=None,\n",
        "    eval_step=500,\n",
        "    ):\n",
        "    record_dict = {\n",
        "        \"train\": [],\n",
        "        \"val\": []\n",
        "    }\n",
        "\n",
        "    global_step = 0\n",
        "    model.train()\n",
        "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
        "        for epoch_id in range(epoch):\n",
        "            # training\n",
        "            for datas, labels in train_loader:\n",
        "                datas = datas.to(device)\n",
        "                labels = labels.to(device)\n",
        "                # 梯度清空\n",
        "                optimizer.zero_grad()\n",
        "                # 模型前向计算\n",
        "                logits = model(datas)\n",
        "                # 计算损失\n",
        "                loss = loss_fct(logits, labels)\n",
        "                # 梯度回传\n",
        "                loss.backward()\n",
        "                # 调整优化器，包括学习率的变动等\n",
        "                optimizer.step()\n",
        "                preds = logits.argmax(axis=-1)\n",
        "\n",
        "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())\n",
        "                loss = loss.cpu().item()\n",
        "                # record\n",
        "\n",
        "                record_dict[\"train\"].append({\n",
        "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
        "                })\n",
        "\n",
        "                # evaluating\n",
        "                if global_step % eval_step == 0:\n",
        "                    model.eval()\n",
        "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
        "                    record_dict[\"val\"].append({\n",
        "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
        "                    })\n",
        "                    model.train()\n",
        "\n",
        "                    # 1. 使用 tensorboard 可视化\n",
        "                    if tensorboard_callback is not None:\n",
        "                        tensorboard_callback(\n",
        "                            global_step,\n",
        "                            loss=loss, val_loss=val_loss,\n",
        "                            acc=acc, val_acc=val_acc,\n",
        "                            lr=optimizer.param_groups[0][\"lr\"],\n",
        "                            )\n",
        "\n",
        "                    # 2. 保存模型权重 save model checkpoint\n",
        "                    if save_ckpt_callback is not None:\n",
        "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
        "\n",
        "                    # 3. 早停 Early Stop\n",
        "                    if early_stop_callback is not None:\n",
        "                        early_stop_callback(val_acc)\n",
        "                        if early_stop_callback.early_stop:\n",
        "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
        "                            return record_dict\n",
        "\n",
        "                # udate step\n",
        "                global_step += 1\n",
        "                pbar.update(1)\n",
        "                pbar.set_postfix({\"epoch\": epoch_id})\n",
        "\n",
        "    return record_dict\n",
        "\n",
        "\n",
        "epoch = 100\n",
        "\n",
        "# 别 20 层了 2333，太深了没法训练\n",
        "model = NeuralNetwork(layers_num=10)\n",
        "\n",
        "# 1. 定义损失函数 采用交叉熵损失\n"
      ],
      "outputs": [],
      "execution_count": 9
    },
    {
      "cell_type": "code",
      "source": [
        "loss_fct = nn.CrossEntropyLoss()"
      ],
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T01:58:27.771727Z",
          "start_time": "2025-01-17T01:58:27.769593Z"
        },
        "id": "lOQNK5mVNdAe"
      },
      "outputs": [],
      "execution_count": 10
    },
    {
      "metadata": {
        "id": "H8Rzw99BNdAf"
      },
      "cell_type": "code",
      "outputs": [],
      "execution_count": 11,
      "source": [
        "# 2. 定义优化器 采用SGD\n",
        "# Optimizers specified in the torch.optim package\n",
        "optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
        "\n",
        "# 1. tensorboard 可视化\n",
        "tensorboard_callback = TensorBoardCallback(\"runs/bn\")\n",
        "tensorboard_callback.draw_model(model, [1, 28, 28])\n",
        "# 2. save best\n",
        "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/bn\", save_best_only=True)\n",
        "# 3. early stop\n",
        "early_stop_callback = EarlyStopCallback(patience=10, min_delta=0.001)\n",
        "\n",
        "model = model.to(device)"
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "\n",
        "record = training(\n",
        "    model,\n",
        "    train_loader,\n",
        "    val_loader,\n",
        "    epoch,\n",
        "    loss_fct,\n",
        "    optimizer,\n",
        "    tensorboard_callback=tensorboard_callback,\n",
        "    save_ckpt_callback=save_ckpt_callback,\n",
        "    early_stop_callback=early_stop_callback,\n",
        "    eval_step=len(train_loader)\n",
        "    )"
      ],
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T02:17:52.703601Z",
          "start_time": "2025-01-17T01:58:27.771727Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 67,
          "referenced_widgets": [
            "38e43f2833ce46369896cd7bf34b64c1",
            "1006f13e1bd74a3aa3684e9d39c42342",
            "cd9f72bdd1be4fb280725cf90392c596",
            "65c7b8f072584623ab3e34e415994b10",
            "81cd926011e342fd9406a7cf77d811cc",
            "6fc4e9ed09c64267b19863c870d317f7",
            "48e7762153ef4d1aba2e973842aa76c1",
            "6b97f71c3f9149dfb5aae7e1742220f6",
            "03aa203de91b40009209e6896c04778e",
            "6afed233ce7448ba93104f5bc332730f",
            "b9ffade05c9b4a33bd7b2f1ee365d6fb"
          ]
        },
        "id": "pryBw2NPNdAf",
        "outputId": "22871675-38d6-49a0-858d-1ad5c139d075"
      },
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "  0%|          | 0/375000 [00:00<?, ?it/s]"
            ],
            "application/vnd.jupyter.widget-view+json": {
              "version_major": 2,
              "version_minor": 0,
              "model_id": "38e43f2833ce46369896cd7bf34b64c1"
            }
          },
          "metadata": {}
        },
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Early stop at epoch 33 / global_step 123750\n"
          ]
        }
      ],
      "execution_count": 12
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T02:17:52.868900Z",
          "start_time": "2025-01-17T02:17:52.703601Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 465
        },
        "id": "szdhw_khNdAg",
        "outputId": "1b3d0ef2-5ce3-480a-fe7b-8646fb4fca4b"
      },
      "source": [
        "#画线要注意的是损失是不一定在零到1之间的\n",
        "def plot_learning_curves(record_dict, sample_step=500):\n",
        "    # build DataFrame\n",
        "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
        "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
        "\n",
        "    # plot\n",
        "    fig_num = len(train_df.columns)\n",
        "    fig, axs = plt.subplots(1, fig_num, figsize=(6 * fig_num, 5))\n",
        "    for idx, item in enumerate(train_df.columns):\n",
        "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
        "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
        "        axs[idx].grid()\n",
        "        axs[idx].legend()\n",
        "        axs[idx].set_xlabel(\"step\")\n",
        "\n",
        "    plt.show()\n",
        "\n",
        "plot_learning_curves(record, sample_step=10000)  #横坐标是 steps"
      ],
      "outputs": [
        {
          "output_type": "display_data",
          "data": {
            "text/plain": [
              "<Figure size 1200x500 with 2 Axes>"
            ],
            "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9UAAAHACAYAAACszkseAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAugBJREFUeJzs3Xd80/X2x/FXkqaLtpTRwSh77yEi4JYhKO5xvd7ruq4r3KtyvSrXgehPue49r9er3useOBGpKCICIqPsvYrQxexu0iS/P75N2tKZNqNt3s/HI4826Tf5fj6lITn5nM85JpfL5UJEREREREREvGYO9gBEREREREREmisF1SIiIiIiIiINpKBaREREREREpIEUVIuIiIiIiIg0kIJqERERERERkQZSUC0iIiIiIiLSQAqqRURERERERBpIQbWIiIiIiIhIA4UFewD14XQ6OXDgALGxsZhMpmAPR0REQpzL5SIvL4+OHTtiNuvzaV/Qa72IiDQ19X29bxZB9YEDB0hJSQn2MERERCrZt28fnTt3DvYwWgS91ouISFNV1+t9swiqY2NjAWMycXFxjXosu93OggULmDhxIlar1RfDaxY0b807FGjeoTVvCN7cc3NzSUlJ8bw+SePptb7xNO/QmjeE7tw1b807UOr7et8sgmp3GlhcXJxPXmijo6OJi4sLuT9GzVvzbuk079CaNwR/7kpT9h291jee5h1a84bQnbvmrXkHWl2v99oIJiIiIiIiItJACqpFREREREREGkhBtYiIiIiIiEgDNYs91SIizYnL5aK0tBSHwxGQ89ntdsLCwiguLg7YOZsKf87dYrEQFhamfdNNSH2fW6H6nGjK87ZarVgslmAPQ0TEL7wKql9++WVefvll9uzZA8DAgQO5//77mTx5co33+eijj7jvvvvYs2cPvXv35tFHH2XKlCmNGrSISFNls9nIyMigsLAwYOd0uVwkJyezb9++kAsA/T336OhoOnToQHh4uM8fW7zjzXMrVJ8TTXneJpOJzp07ExMTE+yhiIj4nFdBdefOnfnnP/9J7969cblcvPXWW5x//vmsWbOGgQMHVjl+6dKlXHHFFcyZM4dzzz2Xd999lwsuuIDVq1czaNAgn01CRKQpcDqd7N69G4vFQseOHQkPDw/IG1un00l+fj4xMTGYzaG1q8dfc3e5XNhsNnJycti9eze9e/cOud9tU+LtcytUnxNNdd4ul4ucnBx+++03evfurRVrEWlxvAqqp06dWun6ww8/zMsvv8zy5curDaqfffZZzj77bP7+978D8NBDD5GamsoLL7zAK6+80ohhi4g0PTabDafTSUpKCtHR0QE7r9PpxGazERkZ2aTeSAeCP+ceFRWF1Wpl7969nnNIcHj73ArV50RTnndCQgJ79uzBbrcrqBaRFqfBe6odDgcfffQRBQUFjBkzptpjli1bxowZMyrdNmnSJD777LNaH7ukpISSkhLP9dzcXMDYK2S32xs6ZM9jVPwaKjRvzTsUBHvedrsdl8sFGG9uA8V9TpfLFdDzNgWBmLvL5aoSCITac6upaGqBotRfU0tHFxHxJa+D6vXr1zNmzBiKi4uJiYlh7ty5DBgwoNpjMzMzSUpKqnRbUlISmZmZtZ5jzpw5zJ49u8rtCxYs8NnqT2pqqk8ep7nRvEOL5h1YYWFhJCcnk5+fj81mC/j58/LyAn7OpsJfc7fZbBQVFbF48WJKS0s9twdyz7yIiIg0bV4H1X379iUtLY1jx47x8ccfc/XVV/Pjjz/WGFg3xMyZMyutcOfm5pKSksLEiROJi4tr1GPb7XZSU1OZMGECVqu1sUNtNjRvzTsUBHvexcXF7Nu3j5iYmICmCrtcLvLy8oiNjQ251SB/z724uJioqChOPfXUSv+m7gwqEREREa+D6vDwcHr16gXAyJEj+fXXX3n22Wd59dVXqxybnJxMVlZWpduysrJITk6u9RwRERFERERUud1qtfrsjbIvH6s50bxDi+YdWA6HA5PJhNlsDmiaqjvt2X3uYOvWrRu33XYbt912W6Mfa9GiRZxxxhkcOXKE+Pj4Kj/399zNZjMmk6nK31RLf14tXryYxx9/nFWrVpGRkcHcuXO54IILar3PokWLmDFjBhs3biQlJYV7772Xa665JiDjDRW+fG6JiIjvNPodiNPprLT/uaIxY8awcOHCSrelpqbWuAdbRESC4/TTT/fZG/Vff/2VG2+80SePJcFRUFDA0KFDefHFF+t1/O7duznnnHM444wzSEtL47bbbuP666/n22+/9fNImz49t0REWj6vVqpnzpzJ5MmT6dKlC3l5ebz77rssWrTI86J51VVX0alTJ+bMmQPArbfeymmnncaTTz7JOeecw/vvv8/KlSt57bXXfD8TERHxG5fLhcPhICys7peNhISEAIxI/Gny5MlMnjy53se/8sordO/enSeffBKA/v37s2TJEp5++mkmTZrkr2G2CHpuiYg0f16tVGdnZ3PVVVfRt29fzjrrLH799Ve+/fZbJkyYAEB6ejoZGRme48eOHcu7777La6+9xtChQ/n444/57LPPgtajet/hQi5+dTmPr1MrBxEJDJfLRaGt1O+XIpujym3uyth1ueaaa/jxxx959tlnMZlMmEwm3nzzTUwmE9988w0jR44kIiKCJUuWsHPnTs4//3ySkpKIiYlh1KhRfPfdd5Uer1u3bjzzzDOe6yaTiddff50LL7yQ6OhoevfuzRdffNHg3+knn3zCwIEDiYiIoEePHrzwwguVfv7SSy/Ru3dvIiMjSUpK4pJLLvH87OOPP2bw4MFERUXRrl07xo8fT0FBQYPHIoZly5Yxfvz4SrdNmjSJZcuW1XifkpIScnNzK12gvNPH8Rd3hXen04nD4SC/2FbjpaDETpHNQUGJvdbjGnJxOByecdR1cdedqfjceuONNzCZTHz99dee59bixYvZvn075513XqXn1oIFCyo9Xrdu3Xj66ac9100mE6+99hoXXHAB0dHR9O3bl3nz5lX6XdV0sdvtXHfddXTv3p2oqCj69u3LM888U+W4119/3fN869ChA9OmTfP87PDhw9x4440kJSURGRnJoEGD+OKLL2o8p7uSvj8utf3t+POyYlcOV7y2jG/W7Q/K+YM592BfgjHv9IN5XP/mCl5ZtJ2SElvIzHt75lFueOtX/v3TzpD696547rp4tVL973//u9afL1q0qMptl156KZdeeqk3p/GbSKuFdb/lAibsDictfEuciDQBRXYHA+4PTgrspgcnER1e93/zzz77LNu2bWPQoEE8+OCDAGzcuBGAu+++myeeeIIePXrQpk0b9u3bx5QpU3j44YeJiIjg7bffZurUqWzdupUuXbrUeI7Zs2fz2GOP8fjjj/P8889z5ZVXsnfvXtq2bevVnFatWsVll13GAw88wOWXX86SJUuYPn06HTt25LrrrmPlypX89a9/5b///S9jx47l8OHD/PTTTwBkZGRwxRVX8Nhjj3HhhReSl5fHTz/9VO8PH6RmNXX7yM3NpaioiKioqCr38abTx/GV9YtsDsY8tdy3k6inZTNOIiq8fh/OP/jgg2zevJkB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ZsPYsWPtbfbu3Quz2Wxvs3v3bgwaNAi+vr72Nj93bJyppqYGcrnjryGFQgGbzQag9+b9U90pz7bE4kyNnezZs2fx7bffwt/f32F7b82bOkdP6+/Z17tXXw+wv7+eu/X33SlH9vWdkHeHljnrQTZt2iQ0Go3YsGGDyM7OFo888ojw8fFxWDWyO3nssceEt7e3SElJEZcvX7Y/ampq7G0WLVokIiIixHfffSfS09NFYmKiSExMtG9vvN3ExIkTxdGjR8WuXbtEnz59WrzdxIoVK8TJkyfFm2++2eLtJlx57K5fEbS35p2WliaUSqV44YUXxNmzZ8VHH30k9Hq9+PDDD+1t1qxZI3x8fMRnn30mjh07JqZNm9bibRhGjRolDh48KPbv3y8GDhzocDuC8vJyERQUJB588EGRlZUlNm3aJPR6fbPbESiVSvG3v/1NnDx5UqxatarTbrExb948ERoaar/FxrZt20RAQID4wx/+0OvyrqysFEeOHBFHjhwRAMSrr74qjhw5Yl/5sjvl2ZZYnJG3yWQSd911lwgLCxNHjx51+F13/eqePTFvch1X91k3gn19E3fo64Vgf9/b+3v29e7b17tNUS2EEG+88YaIiIgQarVajBkzRhw4cMDVIbUKQIuP9evX29vU1taKxx9/XPj6+gq9Xi/uvvtucfnyZYf95ObmijvvvFPodDoREBAgfve73wmz2ezQZs+ePWLkyJFCrVaLfv36OXxGI1ceu592tL0173//+99i2LBhQqPRiJiYGPHuu+86bLfZbOKZZ54RQUFBQqPRiAkTJojTp087tLl27ZqYPXu28PT0FAaDQSxYsEBUVlY6tMnMzBTjx48XGo1GhIaGijVr1jSLZcuWLeKmm24SarVaDB06VHz55ZfOT1gIYTQaxdKlS0VERITQarWiX79+4qmnnnL4Jdtb8t6zZ0+L/6fnzZvX7fJsSyzOyDsnJ6fV33V79uzp0XmTa/WU/p59fRN36euFYH/fm/t79vXu29fLhBCiY2PdRERERERERO7JLa6pJiIiIiIiIuoMLKqJiIiIiIiI2olFNREREREREVE7sagmIiIiIiIiaicW1URERERERETtxKKaiIiIiIiIqJ1YVBMRERERERG1E4tqIiIiIiIionZiUU3UC82fPx/Tp093dRhERETUSdjXE3UfLKqJiIiIiIiI2olFNVEP9umnnyI2NhY6nQ7+/v5ISkrCihUrsHHjRnz22WeQyWSQyWRISUkBABQUFGDmzJnw8fGBn58fpk2bhtzcXPv+Gs96P/fcc+jTpw8MBgMWLVoEk8nkmgSJiIjcHPt6ou5P6eoAiKh9Ll++jNmzZ+Oll17C3XffjcrKSuzbtw9z585Ffn4+jEYj1q9fDwDw8/OD2WzGpEmTkJiYiH379kGpVOKvf/0rJk+ejGPHjkGtVgMAkpOTodVqkZKSgtzcXCxYsAD+/v544YUXXJkuERGR22FfT9QzsKgm6qEuX74Mi8WCe+65B5GRkQCA2NhYAIBOp0N9fT2Cg4Pt7T/88EPYbDb861//gkwmAwCsX78ePj4+SElJwcSJEwEAarUa69atg16vx9ChQ/GXv/wFK1aswPPPPw+5nJNbiIiIugr7eqKegf9riHqoESNGYMKECYiNjcWMGTPw3nvvoaysrNX2mZmZOHfuHLy8vODp6QlPT0/4+fmhrq4O58+fd9ivXq+3f5+YmIiqqioUFBR0aj5ERETkiH09Uc/AkWqiHkqhUGD37t348ccf8c033+CNN97AU089hYMHD7bYvqqqCvHx8fjoo4+abevTp09nh0tEREQ3iH09Uc/AopqoB5PJZBg3bhzGjRuHZ599FpGRkdi+fTvUajWsVqtD27i4OGzevBmBgYEwGAyt7jMzMxO1tbXQ6XQAgAMHDsDT0xPh4eGdmgsRERE1x76eqPvj9G+iHurgwYN48cUXkZ6ejvz8fGzbtg3FxcUYPHgwoqKicOzYMZw+fRolJSUwm82YM2cOAgICMG3aNOzbtw85OTlISUnBE088gcLCQvt+TSYTFi5ciOzsbOzcuROrVq3CkiVLeI0VERFRF2NfT9QzcKSaqIcyGAzYu3cvXnvtNRiNRkRGRuKVV17BnXfeiYSEBKSkpCAhIQFVVVXYs2cP7rjjDuzduxcrV67EPffcg8rKSoSGhmLChAkOZ7MnTJiAgQMH4rbbbkN9fT1mz56NP//5z65LlIiIyE2xryfqGWRCCOHqIIioe5g/fz7Ky8uxY8cOV4dCREREnYB9PZHzcY4HERERERERUTuxqCYiIiIiIiJqJ07/JiIiIiIiImonjlQTERERERERtROLaiIiIiIiIqJ2YlFNRERERERE1E4sqomIiIiIiIjaiUU1ERERERERUTuxqCYiIiIiIiJqJxbVRERERERERO3EopqIiIiIiIionVhUExEREREREbXT/wOhooAaJ5HvMwAAAABJRU5ErkJggg==\n"
          },
          "metadata": {}
        }
      ],
      "execution_count": 13
    },
    {
      "cell_type": "code",
      "metadata": {
        "ExecuteTime": {
          "end_time": "2025-01-17T02:26:54.169169Z",
          "start_time": "2025-01-17T02:26:52.884884Z"
        },
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "s07J6pXhNdAg",
        "outputId": "f0470159-0b5c-4fbe-f1f2-e62d71fc4df6"
      },
      "source": [
        "# dataload for evaluating\n",
        "model=model.to(device)\n",
        "# load checkpoints\n",
        "model.load_state_dict(torch.load(\"checkpoints/bn/best.ckpt\",weights_only=True, map_location=\"cpu\"))\n",
        "\n",
        "model.eval()\n",
        "loss, acc = evaluating(model, val_loader, loss_fct)\n",
        "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
      ],
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "loss:     0.3150\n",
            "accuracy: 0.8886\n"
          ]
        }
      ],
      "execution_count": 14
    },
    {
      "cell_type": "code",
      "source": [],
      "metadata": {
        "id": "U8EBo7uyWbGG"
      },
      "execution_count": null,
      "outputs": []
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.9.7"
    },
    "colab": {
      "provenance": [],
      "gpuType": "T4"
    },
    "accelerator": "GPU",
    "widgets": {
      "application/vnd.jupyter.widget-state+json": {
        "38e43f2833ce46369896cd7bf34b64c1": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "HBoxModel",
          "model_module_version": "1.5.0",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HBoxModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HBoxView",
            "box_style": "",
            "children": [
              "IPY_MODEL_1006f13e1bd74a3aa3684e9d39c42342",
              "IPY_MODEL_cd9f72bdd1be4fb280725cf90392c596",
              "IPY_MODEL_65c7b8f072584623ab3e34e415994b10"
            ],
            "layout": "IPY_MODEL_81cd926011e342fd9406a7cf77d811cc"
          }
        },
        "1006f13e1bd74a3aa3684e9d39c42342": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "HTMLModel",
          "model_module_version": "1.5.0",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6fc4e9ed09c64267b19863c870d317f7",
            "placeholder": "​",
            "style": "IPY_MODEL_48e7762153ef4d1aba2e973842aa76c1",
            "value": " 33%"
          }
        },
        "cd9f72bdd1be4fb280725cf90392c596": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "FloatProgressModel",
          "model_module_version": "1.5.0",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "FloatProgressModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "ProgressView",
            "bar_style": "danger",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6b97f71c3f9149dfb5aae7e1742220f6",
            "max": 375000,
            "min": 0,
            "orientation": "horizontal",
            "style": "IPY_MODEL_03aa203de91b40009209e6896c04778e",
            "value": 123750
          }
        },
        "65c7b8f072584623ab3e34e415994b10": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "HTMLModel",
          "model_module_version": "1.5.0",
          "state": {
            "_dom_classes": [],
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "HTMLModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/controls",
            "_view_module_version": "1.5.0",
            "_view_name": "HTMLView",
            "description": "",
            "description_tooltip": null,
            "layout": "IPY_MODEL_6afed233ce7448ba93104f5bc332730f",
            "placeholder": "​",
            "style": "IPY_MODEL_b9ffade05c9b4a33bd7b2f1ee365d6fb",
            "value": " 123750/375000 [26:57&lt;49:04, 85.32it/s, epoch=32]"
          }
        },
        "81cd926011e342fd9406a7cf77d811cc": {
          "model_module": "@jupyter-widgets/base",
          "model_name": "LayoutModel",
          "model_module_version": "1.2.0",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "6fc4e9ed09c64267b19863c870d317f7": {
          "model_module": "@jupyter-widgets/base",
          "model_name": "LayoutModel",
          "model_module_version": "1.2.0",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "48e7762153ef4d1aba2e973842aa76c1": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "DescriptionStyleModel",
          "model_module_version": "1.5.0",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        },
        "6b97f71c3f9149dfb5aae7e1742220f6": {
          "model_module": "@jupyter-widgets/base",
          "model_name": "LayoutModel",
          "model_module_version": "1.2.0",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "03aa203de91b40009209e6896c04778e": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "ProgressStyleModel",
          "model_module_version": "1.5.0",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "ProgressStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "bar_color": null,
            "description_width": ""
          }
        },
        "6afed233ce7448ba93104f5bc332730f": {
          "model_module": "@jupyter-widgets/base",
          "model_name": "LayoutModel",
          "model_module_version": "1.2.0",
          "state": {
            "_model_module": "@jupyter-widgets/base",
            "_model_module_version": "1.2.0",
            "_model_name": "LayoutModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "LayoutView",
            "align_content": null,
            "align_items": null,
            "align_self": null,
            "border": null,
            "bottom": null,
            "display": null,
            "flex": null,
            "flex_flow": null,
            "grid_area": null,
            "grid_auto_columns": null,
            "grid_auto_flow": null,
            "grid_auto_rows": null,
            "grid_column": null,
            "grid_gap": null,
            "grid_row": null,
            "grid_template_areas": null,
            "grid_template_columns": null,
            "grid_template_rows": null,
            "height": null,
            "justify_content": null,
            "justify_items": null,
            "left": null,
            "margin": null,
            "max_height": null,
            "max_width": null,
            "min_height": null,
            "min_width": null,
            "object_fit": null,
            "object_position": null,
            "order": null,
            "overflow": null,
            "overflow_x": null,
            "overflow_y": null,
            "padding": null,
            "right": null,
            "top": null,
            "visibility": null,
            "width": null
          }
        },
        "b9ffade05c9b4a33bd7b2f1ee365d6fb": {
          "model_module": "@jupyter-widgets/controls",
          "model_name": "DescriptionStyleModel",
          "model_module_version": "1.5.0",
          "state": {
            "_model_module": "@jupyter-widgets/controls",
            "_model_module_version": "1.5.0",
            "_model_name": "DescriptionStyleModel",
            "_view_count": null,
            "_view_module": "@jupyter-widgets/base",
            "_view_module_version": "1.2.0",
            "_view_name": "StyleView",
            "description_width": ""
          }
        }
      }
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}